再加入 迴轉功能卡 進入勝利判斷之前
我想整理一下判斷勝利相關的方法
目前是否執行 結束回合是由 maybe_end_round 方法的 guard 判斷當下 turn 是否大於 3 來決定的
我想與其把判斷勝利放在 maybe_end_round 裡面,不如我放在 maybe_end_round 前面,也由 turn 是否大於 3 來決定
看看有沒有比較好用。
把原本從 compare_score/3 開頭的方法改成下面
defp maybe_add_wins(%{turn: turn} = game) when turn > 3 do
scores = calculate_score(game)
if scores.host > scores.guest do
assign_to_player(game, :host, :wins, game.host.wins + 1)
else
assign_to_player(game, :guest, :wins, game.guest.wins + 1)
end
end
defp maybe_add_wins(game), do: game
defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
[host_score, guest_score] =
[host_desk, guest_desk]
|> Enum.map(&Enum.slice(&1, (round - 1)..(round * 3 - 1)))
|> Enum.map(&Enum.sum(&1))
%{host: host_score, guest: guest_score}
end
現在 handle_cast :play_card 方法多了拉到這個層級的 maybe_add_wins 方法
def handle_cast({:play_card, player, card}, game) do
game =
game
|> play_card_for(player, card)
|> maybe_end_turn()
|> maybe_add_wins()
|> maybe_end_round()
{:noreply, game}
end
每個都 maybe 好像有點瞎,都拿掉好了
def handle_cast({:play_card, player, card}, game) do
game =
game
|> play_card_for(player, card)
|> end_turn()
|> add_wins()
|> end_round()
{:noreply, game}
end
我現在才發現我在 struct 把迴轉卡叫 :turn ,跟回合的 turn 好像有點撞到,
改成 :reverse 又很長,不過為了避免各種誤會還是改一下好了
initial_hand = [1, 1, 2, 2, 3, 3, 4, 5, 6, :reverse, :reverse]
因為我們在計算分數是用加的
所以要再計算前把 reverse 拿掉
應該是放在這個計算方法
defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
[host_score, guest_score] =
[host_desk, guest_desk]
|> Enum.map(&Enum.slice(&1, (round - 1)..(round * 3 - 1)))
|> Enum.map(&擋掉(:reverse))
|> Enum.map(&Enum.sum(&1))
%{host: host_score, guest: guest_score}
end
我們可以用 Enum.reject(enumerable, fun)
方法
Enum.reject([1, 2, :reverse], fn card -> card == :reverse end)
就變成
defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
[host_score, guest_score] =
[host_desk, guest_desk]
|> Enum.map(&Enum.slice(&1, (round - 1)..(round * 3 - 1)))
|> Enum.map(&Enum.reject(&1, fn card -> card == :reverse end))
|> Enum.map(&Enum.sum(&1))
%{host: host_score, guest: guest_score}
end
再來是 :reverse 的效果是可以疊加的
我出一張 :reverse 你出一張 :reverse 的效果會抵銷 依此類推
我猜可能要先數 :reverse 有幾張,偶數就用沒事,
奇數就在比較分數的時候用一下 not 方法
not(true) #=> false
not(host_score > guest_score)
於是判斷是不是 host 贏的地方被我加了一個 apply_reverse/2 來決定要不要套用 not
defp add_wins(%{turn: turn} = game) when turn > 3 do
scores = calculate_score(game)
if apply_reverse((scores.host > scores.guest), scores.reverse) do
assign_to_player(game, :host, :wins, game.host.wins + 1)
else
assign_to_player(game, :guest, :wins, game.guest.wins + 1)
end
end
defp apply_reverse(compare, true), do: not(compare)
defp apply_reverse(compare, false), do: compare
至於這局要不要 套用我目前把做法放進 calculate_score 他有我們這次所需要的數值們,
很顯然的,這又讓calculate_socre這個方法做太多事了,沒關係我們先把作法變出來
defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
[host_cards, guest_cards] =
Enum.map([host_desk, guest_desk], &Enum.slice(&1, (round - 1)..(round * 3 - 1)))
[host_score, guest_score] =
[host_cards, guest_cards]
|> Enum.map(&Enum.reject(&1, fn card -> card == :reverse end))
|> Enum.map(&Enum.sum(&1))
reverse =
[host_desk, guest_desk]
|> Enum.map(&Enum.filter(&1, fn card -> card == :reverse end))
|> List.flatten()
|> length()
|> rem(2) == 1
%{host: host_score, guest: guest_score, reverse: reverse}
end
在利用 slice 取得當前這局雙方的卡後,除了使用 reject 去掉 :reverse 繼續算分數外
還有用他們套進 filter 取出所有的 :reverse,用 flatten 把它們混再一起後
算長度除 2 在比比看 是不是 1,就可以得到這局要不要 reverse
最後在 iex 試玩一下
現在試玩的步驟變得超長到我想要寫個腳本...
iex(1)> import Game
Game
iex(2)> {:ok, pid} = start
{:ok, #PID<0.113.0>}
iex(3)> play_card pid, :host, 1
:ok
iex(4)> play_card pid, :guest, 2
:ok
iex(5)> play_card pid, :host, :reverse
:ok
iex(6)> play_card pid, :guest, :reverse
:ok
iex(7)> play_card pid, :host, :reverse
:ok
iex(8)> play_card pid, :guest, 3
:ok
iex(9)> status pid
%Game{
guest: %{
desk: [2, :reverse, 3],
hand: [1, 1, 2, 3, 4, 5, 6, :reverse],
wins: 0
},
host: %{
desk: [1, :reverse, :reverse],
hand: [1, 2, 2, 3, 3, 4, 5, 6],
wins: 1
},
round: 2,
turn: 1
}